/*
**  File: AquaRedun.c
**
**  This file is part of the AQUA program suite, which is being
**  developed in the NMR Spectroscopy Department, Bijvoet Center for 
**  Biomolecular Research, Utrecht, the Netherlands and the BioMagResBank, 
**  University of Wisconsin-Madison, USA.

**
**  VERSION   : 3.2
**  DATE      : Jan, 2001
 
    MERGED INTO AQUA 1.5 on Dec 11, 1997

    AUTHOR(S) : Jurgen F. Doreleijers based on programs by Ton Rullmann 
    PURPOSE   : conservative filtering of redundant intra residual restraints
                see files doc/redun_method.txt and doc/redun_output.txt

    OPTIONS:
    Redundancy on lower or upper bound ONLY           : DELREDL,DELREDU
    Restraints including pseudo-atoms can be skipped  : SAVPSEU
    The target distance can be used as lower bound    : USEDIST
    Threshold of redundancy  in percent               : THRESH
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "Compiler.h"
#include "General.h"

#include "AquaMacros.h"
#include "AquaTypes.h"
#include "AquaTypes_Assign.h"

/****************  function prototypes  ****************/

#include "AquaFuncts.h"
#include "AquaFuncts_dr.h"
#include "AquaStrucset.h"
#include "AquaFiles.h"
#include "MenuFuncts.h"
#include "Functs.h"

#include "AquaRedun.h"
#include "AquaCommon.h"
#include "nrutil.h"


/****************  globals  ****************/

extern Boolean  iaf, batch;                           /* import from Functs */
extern int      terseness;                            /* import from Functs */
char            *program_name = "AquaRedundant";      /* export to Functs */
char            *program_vers = aqua_version;         /* export to Functs */
char            temp_value[4];

/* My own globals */

enum { opt_ext, opt_detail, 
       opt_savpseu, opt_delredu, opt_delredl, opt_usedist, opt_thresh };

/* BEGIN_EXTH */

int main( int argc, char *argv[] )
{
    char         *fct_name = "AquaRedun main";
    Strucset     theSet;
    DistdataList inf_list, val_list;
    DistinfTyp   ftype = inf_normal;
    Qtyp         qtype;
    int          s_count, count;
    Filnam       dinf_filnam, drst_filnam;
    Filnam       filnam_s, filnam_r;
    Card         ident;
    int          item;
    
/* My own variables */
    
    Mol		*molptr;				    	    
    Atom	*atoms;
    Distinf	*dist_inf;
    Distrst	*dist_rst;
    Distval	thresh;
    int		dist_count;
    int		red_count;
    DRList      DR_list;
    Boolean	detail;
    Boolean     save_pseudos, del_red_l, del_red_u, use_distance;
    
    enum { item_do };
    static MenuItem menulist[] =
    {
        { item_EXEC,  "exec",  none, on },
        { item_SET,   "set",   none, on },
        { item_do,    "do",    none, on }, 
        { item_QUIT,  "quit",  none, on } 
    };
    static OptionItem optionlist[] =
    {
        { opt_batch,       "batch",       logical, on }, 
        { opt_terseness,   "terseness",   integer, on }, 
        { opt_prtaq,       "print",       logical, on }, 
        { opt_ext,         "useext",      logical, on }, 
        { opt_prtres,      "printres",    logical, on }, 
        { opt_delredl,     "delredl",     logical, on }, 
        { opt_delredu,     "delredu",     logical, on }, 
        { opt_savpseu,     "savpseu",     logical, on }, 
        { opt_usedist,     "usedist",     logical, on }, 
        { opt_detail,      "detail",      logical, on }, 
        { opt_thresh,      "thresh",      real,    on }, 
        { opt_guess,       "guess",       logical, on }
    };

    static Menu menu =
    {
        "Main menu", "command", "Give command:", 
        sizeof(menulist)/sizeof(MenuItem)
    };
    static Menu options =
    {
        "Options menu", "option", "Give option:", 
        sizeof(optionlist)/sizeof(MenuItem)
    }; 


/* initialize */

    inf_list.count = 0;
    val_list.count = 0;

    ProgramInit( argc, argv );
    ProjectInit();
    StrucsetInit( &theSet, "theSet", true );
    SetMenu( &menu, menulist );
    SetOptions( &options, optionlist );
    ModOption( opt_thresh, "5.0" );
    ModOption( opt_detail, "true" );
    sprintf( temp_value, "%d", terseness );
    ModOption( opt_terseness, temp_value );    
    
/* the main menu loop */

    while ( true )
    {
        item = ReadMenuItem();
        switch ( item )
        {
            case item_EXEC:
		DoExec();
                break;
            case item_SET:
		ReadOption();
		batch = OptionTrue( opt_batch );
                if ( !Check_General_Options () ) {
	            printf( "Error in main: general options set are not okay\n" );
	            MError( );
                }
                terseness   = GetOptionIVal ( opt_terseness );                
                break;
            case item_do:
		goto doit;
            case item_QUIT:
            case item_NULL:
                exit( 0 );
                break;
            default:
                ProcessMenuError( menu_fatal );
                break;
        }
    }

/* do the main thing */

doit:

/* process the distance-restraints file */

    *drst_filnam = '\0';
    dist_rst = ProcessDistrstFile( &dist_count, &qtype, theSet.filnam, dinf_filnam, 
                                   ident, true, drst_filnam );

/* process the distance-info file (file name read from distance-restraints file) */

    if ( IsEmptyStr( dinf_filnam ) )
    {
	FATAL( " * Name of dist-info file not found on distance-restraints file");
    }
    ProcessDistinfFile( &inf_list, &count, &s_count, &qtype, filnam_s, filnam_r,
                        ident, false, &ftype, dinf_filnam );


    dist_inf = NULL; /* For compiler checks */
    
    if ( ftype == inf_normal ) {
	    dist_inf = (Distinf	*)(inf_list.fst_desc->data);
    } else {
	    FATAL( "Wrong file/data type - Code error" );
    }
    
    if ( NOTEQ( theSet.filnam, filnam_s ) ||
         NOTEQ( drst_filnam, filnam_r )   ||
         dist_count != count )
    {
        nrerror(" * Inconsistent information on info and restraints files");
    }

    if ( terseness < 6 ) {
        printf ("Read %d restraints\n", dist_count);
    
/* open and read the strucset file */
    printf("open and read the strucset file\n");
    }

    if ( EMPTYSET( theSet ) )
    {
	if ( !ProcessStrucsetFile( &theSet, 0 ) )
	    exit( 1 );
    }
    
    molptr	= theSet.molecule;
    atoms	= molptr->atoms;
     
     
     
/* Redun specific routines */
    

/* Get distance restraints from dist_inf and dist_rst*/    

    MakeDRList( &DR_list, dist_inf, dist_rst, dist_count, atoms );
    if ( DR_list.list == NULL )
        nrerror( " * Wrong init" );
    

/* Mark redundant restraints with keep flag false,
    skip those flagged false for keep flag */

    save_pseudos    = OptionTrue( opt_savpseu );
    del_red_l       = OptionTrue( opt_delredl );
    del_red_u       = OptionTrue( opt_delredu );
    use_distance    = OptionTrue( opt_usedist );

    thresh          = GetOptionRVal( opt_thresh );
    detail          = OptionTrue( opt_detail );

    red_count = Check_Redundant  ( DR_list.list, dist_count, 0, detail, 
		save_pseudos, del_red_l, del_red_u, 
		use_distance, thresh );
    
    
/* Write distance restraints to a noe file */

    printf("Will write %d remaining restraints.\n", dist_count-red_count);

    ProcessDROutput( &DR_list, red_count, "noe", false, molptr, theSet.struc_count);


    if ( terseness < 6 ) {
        printf("Finished AquaRedundant, have a nice day\n\n");
    }
    exit(0);
    
}
